package cn.keniykey.mc.viewlibrary.reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;

import javax.annotation.Nullable;

public final class SearchReflectionConstructor implements Cloneable{
	private EReflectionPermission permission;
	private LinkedList<Class<?>[]> parameter;
	
	private final int constructors_index;
	
	public SearchReflectionConstructor(int index) {
		this.constructors_index = index;
	}
	public SearchReflectionConstructor() {
		this.constructors_index = 0;
	}
	
	public SearchReflectionConstructor setPermission(@Nullable EReflectionPermission per) {
		this.permission = per;
		return this;
	}
	public SearchReflectionConstructor addParameter(Class<?>...classes) {
		if(this.parameter == null) this.parameter = new LinkedList<>();
		this.parameter.add(classes);
		return this;
	}
	public SearchReflectionConstructor nonParameter() {
		if(this.parameter == null) {
			this.parameter = new LinkedList<>();
		}else {
			this.parameter.clear();
		}
		return this;
	}
	ArrayList<Constructor<?>> findConstructors(Class<?> clazz) {
		final HashSet<Constructor<?>> hashset_constructors = new HashSet<>();
		Collections.addAll(hashset_constructors, clazz.getConstructors());
		Collections.addAll(hashset_constructors, clazz.getDeclaredConstructors());
		final LinkedList<Constructor<?>> constructors = new LinkedList<>(hashset_constructors);
		hashset_constructors.clear();
		final Iterator<Constructor<?>> it = constructors.iterator();
		constructor_while : while(it.hasNext()) {
			final Constructor<?> constructor = it.next();
			if(this.permission != null && !this.permission.isModifiers(constructor.getModifiers())) {
				it.remove();
				continue;
			}
			if(this.parameter != null) {
				final Type[] partypes = constructor.getGenericParameterTypes();
				if(partypes.length != this.parameter.size()) {
					it.remove();
					continue;
				}
				int index = 0;
				for(final Class<?>[] classes : this.parameter) {
					final Object obj = ReflectionGenericClass.getParameterClasses(partypes[index]);
					index++;
					if(obj instanceof Class) {
						if(classes.length != 1 || !obj.equals(classes[0])) {
							it.remove();
							continue constructor_while;
						}
					}else if(obj instanceof LinkedList) {
						final LinkedList<?> linkeds = (LinkedList<?>) obj;
						if(linkeds.size() != classes.length) {
							it.remove();
							continue constructor_while;
						}
						int in = 0;
						for(final Object forobj : linkeds) {
							if(!forobj.equals(classes[in])) {
								it.remove();
								continue constructor_while;
							}
							in++;
						}
					}
				}
			}
		}
		try {
			return new ArrayList<>(constructors);
		}finally {
			constructors.clear();
		}
	}
	Constructor<?> findConstructor(final Class<?> clazz) {
		final ArrayList<Constructor<?>> constructors = this.findConstructors(clazz);
		if(constructors.isEmpty()) throw new RuntimeException("cannot get the constructor(NoSuchMethodException)(获取不到指定Constructor方法)");
		try {
			if(this.constructors_index >= constructors.size()) throw new RuntimeException("the such constructor index out of found constructors amount"
					+ "(IndexOutOfBoundsException)(需求方法索引位置超出目前搜到的上限): " + this.constructors_index + "/" + constructors.size());
			return constructors.get(this.constructors_index);
		}finally {
			constructors.clear();
		}
	}
	@Override
	public String toString() {
        final StringBuilder b = new StringBuilder(this.getClass().getSimpleName() + "{");
        if(this.permission != null) {
        	b.append("[permission:").append(this.permission.toString()).append("]");
        }
        if (this.parameter != null) {
            b.append("[parameter:").append(this.parameter.toString()).append("]");
        }
        b.append("[index:").append(this.constructors_index).append("]");
        b.append("}");
        return b.toString();
	}
	@Override
	public SearchReflectionConstructor clone() {
		final SearchReflectionConstructor search = new SearchReflectionConstructor(this.constructors_index);
		search.permission = this.permission;
		if(this.parameter != null) {
			search.parameter = new LinkedList<>();
			for(final Class<?>[] classes : this.parameter) {
				search.parameter.add(Arrays.copyOf(classes, classes.length));
			}
		}
		return search;
	}
}